package com.xiaoyu.tio.redis.core.pool;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

import com.xiaoyu.tio.redis.config.TedisConfig;
import com.xiaoyu.tio.redis.core.Tedis;

public class TedisPool implements Pool<Tedis>{
	
	private TedisConfig tedisConfig;
	
	private int maxIdle = 10;
	
	private int maxActive = 100;
	
	private AtomicInteger freeSize = new AtomicInteger(0);
	
	private AtomicInteger usedSize = new AtomicInteger(0);
	
	private AtomicInteger totalSize = new AtomicInteger(0);
	
	private ConcurrentLinkedQueue<Tedis> freeQueue = new ConcurrentLinkedQueue<>();
	
	private ConcurrentLinkedQueue<Tedis> usedQueue = new ConcurrentLinkedQueue<>();
	
	public TedisPool(TedisConfig config) {
		tedisConfig = config;
	}
	
	public TedisPool(TedisConfig config, int maxIdle, int maxActive) {
		this.maxIdle = maxIdle;
		this.maxActive = maxActive;
		this.tedisConfig = config;
	}
	

	@Override
	public Tedis get() {
		Tedis c = freeQueue.poll();
		if(c == null) {
			if(totalSize.get() < maxActive) {
				c = makeClient();
				usedQueue.add(c);
				totalSize.incrementAndGet();
				usedSize.incrementAndGet();
			}else {
				while (true) {
					c = freeQueue.poll();
					if(c == null) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}else {
						usedQueue.add(c);
						freeSize.decrementAndGet();
						usedSize.incrementAndGet();
						break;
					}
				}
			}
		}else {
			usedQueue.add(c);
			freeSize.decrementAndGet();
			usedSize.incrementAndGet();
		}
		return c;
	}

	@Override
	public void release(Tedis c) {
		if(c.isActive()) {
			if(totalSize.get() < maxIdle) {
				if(freeQueue.add(c)) {
					freeSize.incrementAndGet();
				}
				if(usedQueue.remove(c)) {
					usedSize.decrementAndGet();
				}
			}else {
				if(usedQueue.remove(c)) {
					usedSize.decrementAndGet();
					totalSize.decrementAndGet();
				}
				c.close();
			}
		}else {
			if(usedQueue.remove(c)) {
				usedSize.decrementAndGet();
				totalSize.decrementAndGet();
			}
			c.close();
		}	
	}


	public int getMaxIdle() {
		return maxIdle;
	}

	private Tedis makeClient() {
		Tedis c = new Tedis<>(tedisConfig);
		try {
			c.connect();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return c;
	}

	public void setMaxIdle(int maxIdle) {
		this.maxIdle = maxIdle;
	}


	public int getMaxActive() {
		return maxActive;
	}


	public void setMaxActive(int maxActive) {
		this.maxActive = maxActive;
	}

}
